//============================================================================
// Name        : CSBTreeDemo.cpp
// Author      : dhonegger
// Version     :
// Copyright   : cmpe226
// Description : CSB+ Tree test program, Ansi-style
//============================================================================

#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <limits.h>

#include "../database-cmpe226/StorageManager/Student.h"
#include "../database-cmpe226/StorageManager/StorageManager.h"
#include "../database-cmpe226/CsbTree/CsbIndex.h"

using namespace std;

#define MAX_RECORDS 2000000

#define PART1 1
#define PART2 0

double clockElapsedToMs(clock_t start, clock_t end)
{
	double diffticks=end-start;
	double diffms=(diffticks*1000)/CLOCKS_PER_SEC;
	return diffms;
}

int main() {
	cout << "CSBPlusTree" << endl << "RAND_MAX: " << RAND_MAX << endl << endl; //prints Test Storage Manager

	//preallocate 2 million records
	StorageManager *sm = new StorageManager();

	Page *pg;
	srand(time(NULL));
	unsigned int randKey;

	int idx;

	for(idx = 0; idx < MAX_RECORDS; idx++) {
		pg = sm->AllocatePage();
		randKey = rand() % INT_MAX;
		pg->GetRecordLocation()->SetStudent(randKey, "last", "first", "addy", rand() % 100);
	}

	if(PART1) {
		cout << "PART 1" << endl;
		Record *recPtr;
		CsbIndex *demoIdx = new CsbIndex(Node::GetD());
		for(idx = 0; idx < 100; idx++)
		{
			recPtr = sm->FetchRecord(idx);
			cout << "Iteration " << idx << ", insert key: " << recPtr->GetStudent()->GetSsn() << endl;
			if(demoIdx->searchRecord(recPtr->GetStudent()->GetSsn()) == NULL) {
				demoIdx->insertRecord(recPtr->GetStudent()->GetSsn(), recPtr);
				demoIdx->printIndex();
				cout << endl << endl;
			}
			else
				cout << "index collision on: " << recPtr->GetStudent()->GetSsn() << endl;
		}

		demoIdx->printIndex();
		//demoIdx->printKeys();
		cout << endl << endl;

		unsigned int searchKey;
		bool searching = true;
		unsigned int prevKey;

		while(searching) {
			cout << "Input key to search for (enter 0 twice to exit)-->" << endl;
			cin >> searchKey;
			if(prevKey == searchKey && searchKey == 0)
				break;
			prevKey = searchKey;

			recPtr = demoIdx->searchRecord(searchKey);
			if(recPtr == NULL)
				cout << "record not found" << endl;
			else
				cout << "found, info: " << recPtr->GetStudent()->GetStudentString() << endl;
		}

		delete demoIdx;
	}

	if(PART2) {
		cout << "PART 2" << endl;
		Record *recPtr;
		double milMs, twoMilMs, searchMs, randomOpMs;
		int numSearch = 0, numInsert = 0;

		CsbIndex *milIdx = new CsbIndex(Node::GetD());
		CsbIndex *twoMilIdx = new CsbIndex(Node::GetD());

		//Part A
		clock_t start = clock();
		for(idx = 0; idx < 1000000; idx++)
		{
			recPtr = sm->FetchRecord(idx);
			milIdx->insertRecord(recPtr->GetStudent()->GetSsn(), recPtr);
		}
		milMs = clockElapsedToMs(start, clock());

		start = clock();
		for(idx = 0; idx < 2000000; idx++)
		{
			recPtr = sm->FetchRecord(idx);
			twoMilIdx->insertRecord(recPtr->GetStudent()->GetSsn(), recPtr);
		}
		twoMilMs = clockElapsedToMs(start, clock());

		//Part B
		start = clock();
		for(idx = 0; idx < 100000; idx++) {
			recPtr = twoMilIdx->searchRecord(rand() % INT_MAX);
		}
		searchMs = clockElapsedToMs(start, clock());

		//Part C
		start = clock();
		for(idx = 0; idx < 100000; idx++) {
			if(rand() % 2) {
				recPtr = sm->FetchRecord(1000000 + idx);
				milIdx->insertRecord(recPtr->GetStudent()->GetSsn(), recPtr);
				numInsert++;
			}
			else {
				recPtr = milIdx->searchRecord(rand() % INT_MAX);
				numSearch++;
			}
		}
		randomOpMs = clockElapsedToMs(start, clock());

		cout << "Time for 1,000,000 inserts: " << milMs << " ms" << endl
				<< "Time for 2,000,000 inserts: " << twoMilMs << " ms" << endl
				<< "Time for 100,000 searches: " << searchMs << " ms" << endl
				<< "Time for " << numInsert << " inserts, " << numSearch << " searches: " << randomOpMs << " ms" << endl;

		delete milIdx;
		delete twoMilIdx;
	}

	delete sm;

//	cout << endl << "Performance logged.  Press enter to exit..." << endl;
//
//	string input;
//	cin >> input;

	return 0;
}
